
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Animation Plugin</title>

<style type="text/css">
/*margin and padding on body element
  can introduce errors in determining
  element position and are not recommended;
  we turn them off as a foundation for YUI
  CSS treatments. */
body {
	margin:0;
	padding:0;
}
</style>

<link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" />
<script type="text/javascript" src="../../build/yui/yui-min.js"></script>


<!--begin custom header content for this example-->
<style type="text/css">
    /* If js is enabled, hide overlay markup off screen while the overlay is being instantiated */
    .yui3-js-enabled .yui3-overlay-loading {
        top:-1000em;
        left:-1000em;
        position:absolute;
    }

    .yui3-overlay-content {
        background-color:#ccc;
        border:1px solid #000;
        padding:5px;
    }

    .yui3-overlay .yui3-widget-hd, 
    .yui3-overlay .yui3-widget-bd, 
    .yui3-overlay .yui3-widget-ft {
        background-color:#eee;
        padding:2px;
        border:1px solid #999;
    }

    .yui3-overlay .yui3-widget-bd {
        background-color:#fff;
    } 
</style>

<!--end custom header content for this example-->

</head>

<body class="yui3-skin-sam  yui-skin-sam">

<h1>Animation Plugin</h1>

<div class="exampleIntro">
	<p>This example shows how you can use Widget's plugin infrastructure to customize the existing behavior of a widget.</p>

<p>We create an Animation plugin class for Overlay called <code>AnimPlugin</code> which changes the way Overlay instances are shown/hidden, by fading them in and out. The Overlay is initially constructed with the <code>AnimPlugin</code> plugged in <em>(with the duration set to 2 seconds)</em>.
Clicking the "Unplug AnimPlugin" button, will restore the original non-Animated Overlay show/hide behavior. Clicking on the "Plug AnimPlugin" button will plug in the <code>AnimPlugin</code> again, but with a shorter duration.</p>

<p>NOTE: This example serves as a tutorial for how to build your own plugins. A packaged animation plugin based on this example is available by using the <code>widget-anim</code> module, which sets up a <a href="../../api/WidgetAnim.js.html"><code>Y.Plugin.WidgetAnim</code></a> class, similar to the one discussed in this example.</p>
			
</div>

<!--BEGIN SOURCE CODE FOR EXAMPLE =============================== -->

<div id="overlay" class="yui3-overlay-loading">
    <div class="yui3-widget-hd">Overlay Header</div>
    <div class="yui3-widget-bd">Overlay Body</div>
    <div class="yui3-widget-ft">Overlay Footer</div>
</div>

<button type="button" id="show">Show</button>
<button type="button" id="hide">Hide</button>
<button type="button" id="unplug">Unplug AnimPlugin</button>
<button type="button" id="plug">Plug AnimPlugin (duration:0.5)</button>

<script type="text/javascript">
YUI().use("overlay", "anim", "plugin", function(Y) {

    /* Animation Plugin Constructor */
    function AnimPlugin(config) {
        AnimPlugin.superclass.constructor.apply(this, arguments);
    }

    /* 
     * The namespace for the plugin. This will be the property on the widget, which will 
     * reference the plugin instance, when it's plugged in
     */
    AnimPlugin.NS = "fx";

    /*
     * The NAME of the AnimPlugin class. Used to prefix events generated
     * by the plugin class.
     */
    AnimPlugin.NAME = "animPlugin";

    /*
     * The default set of attributes for the AnimPlugin class.
     */
    AnimPlugin.ATTRS = {

        /*
         * Default duration. Used by the default animation implementations
         */
        duration : {
            value: 0.2
        },

        /*
         * Default animation instance used for showing the widget (opacity fade-in)
         */
        animVisible : {
            valueFn : function() {

		var host = this.get("host");
                var boundingBox = host.get("boundingBox");

                var anim = new Y.Anim({
                    node: boundingBox,
                    to: { opacity: 1 },
                    duration: this.get("duration")
                });

                // Set initial opacity, to avoid initial flicker
                if (!host.get("visible")) {
                    boundingBox.setStyle("opacity", 0);
                }

                // Clean up, on destroy. Where supported, remove
                // opacity set using style. Else make 100% opaque
                anim.on("destroy", function() {
                    if (Y.UA.ie) {
                        this.get("node").setStyle("opacity", 1);
                    } else {
                        this.get("node").setStyle("opacity", "");
                    }
                });

                return anim;
            }
        },

        /*
         * Default animation instance used for hiding the widget (opacity fade-out)
         */
        animHidden : {
            valueFn : function() {
                return new Y.Anim({
                    node: this.get("host").get("boundingBox"),
                    to: { opacity: 0 },
                    duration: this.get("duration")
                });
            }
        }
    }

    /*
     * Extend the base plugin class
     */
    Y.extend(AnimPlugin, Y.Plugin.Base, {

        /*
         * Initialization code. Called when the 
         * plugin is instantiated (whenever it's 
         * plugged into the host)
         */
        initializer : function(config) {
            this._bindAnimVisible();
            this._bindAnimHidden();

            this.after("animVisibleChange", this._bindAnimVisible);
            this.after("animHiddenChange", this._bindAnimHidden);

            // Override default _uiSetVisible method, with custom animated method
            this.doBefore("_uiSetVisible", this._uiAnimSetVisible);
        },

        /*
         * Destruction code. Invokes destroy in the individual animation instances,
         * and lets them take care of cleaning up any state.
         */
        destructor : function() {
            this.get("animVisible").destroy();
            this.get("animHidden").destroy();
        },

        /*
         * The custom animation method, added by the plugin.
         *
         * This method replaces the default _uiSetVisible handler
         * Widget provides, by injecting itself before _uiSetVisible,
         * (using Plugins before method) and preventing the default
         * behavior.
         */
        _uiAnimSetVisible : function(val) {
            if (this.get("host").get("rendered")) {
                if (val) {
                    this.get("animHidden").stop();
                    this.get("animVisible").run();
                } else {
                    this.get("animVisible").stop();
                    this.get("animHidden").run();
                }
                return new Y.Do.Prevent("AnimPlugin prevented default show/hide");
            }
        },

        /*
         * The original Widget _uiSetVisible implementation
         */
        _uiSetVisible : function(val) {
            var host = this.get("host");
            var hiddenClass = host.getClassName("hidden");
            if (!val) {
                host.get("boundingBox").addClass(hiddenClass);
            } else {
                host.get("boundingBox").removeClass(hiddenClass);
            }
        },

        /* Sets up call to invoke original visibility handling when the animVisible animation is started */
        _bindAnimVisible : function() {
            var animVisible = this.get("animVisible");

            // Setup original visibility handling (for show) before starting to animate
            animVisible.on("start", Y.bind(function() {
                this._uiSetVisible(true);
            }, this));
        },

        /* Sets up call to invoke original visibility handling when the animHidden animation is complete */
        _bindAnimHidden : function() {
            var animHidden = this.get("animHidden");

            // Setup original visibility handling (for hide) after completing animation
            animHidden.after("end", Y.bind(function() {
                this._uiSetVisible(false);
            }, this));
        }
    });

    // Create a new Overlay instance, and add AnimPlugin with a default duration of 2 seconds
    var overlay = new Y.Overlay({
        srcNode: "#overlay",
        width:"10em",
        height:"10em",
        visible:false,
        shim:false,
        align: {
            node: "#show", 
            points: ["tl", "bl"]
        },
        plugins : [{fn:AnimPlugin, cfg:{duration:2}}]
    });
    overlay.render();

    Y.on("click", function() {
        overlay.show();
    }, "#show");

    Y.on("click", function() {
        overlay.hide();
    }, "#hide");

    Y.on("click", function() {
        overlay.unplug("fx");
    }, "#unplug");

    Y.on("click", function() {
        overlay.unplug("fx");
        overlay.plug(AnimPlugin, {duration:0.5});
    }, "#plug");

});
</script>

<!--END SOURCE CODE FOR EXAMPLE =============================== -->

</body>
</html>
